﻿#include "ais_box.h"
#include "ais_curve.h"
#include "ais_mesh.h"
#include "ais_pointcloud.h"
#include "ais_surface.h"
#include "algo/algo_bounding.h"
#include "kernel/convex.h"
#include "kernel/transform.h"

CAGD::AIS_Box::AIS_Box()
{
    m_info.active = false;
    m_info.size = 20;
    m_info.status = AIS_Status::HIDDEN;
    m_info.color = {1.0, 1.0, 1.0, 1.0};
}

void CAGD::AIS_Box::UpdateArray()
{
    // 计算包围盒
    auto parent = GetParent();
    switch (parent->GetType())
    {
    case AIS_Type::CURVE: {
        AIS_Curve *cur = dynamic_cast<AIS_Curve *>(parent);
        m_box = Bounding<double>::OBB(GeomCurve::UniformPointSample(cur->GetCurve(), cur->GetInfo().size));
        break;
    }
    case AIS_Type::POINTCLOUD: {
        AIS_PointCloud *pc = dynamic_cast<AIS_PointCloud *>(parent);
        m_box = Bounding<double>::OBB(pc->GetPoints());
        break;
    }
    case AIS_Type::MESH: {
        AIS_Mesh *mesh = dynamic_cast<AIS_Mesh *>(parent);
        m_box = Bounding<float>::OBB(mesh->GetMesh()->vertices);
        break;
    }
    case AIS_Type::SURFACE: {
        AIS_Surface *sur = dynamic_cast<AIS_Surface *>(parent);
        m_box = Bounding<float>::OBB(sur->GetMesh()->vertices);
        break;
    }
    }

    AIS_Base::UpdateArray();
}

CAGD::AIS_Type CAGD::AIS_Box::GetType() const
{
    return AIS_Type::BOX;
}

void CAGD::AIS_Box::UpdateInfo()
{
    // 继承模型矩阵
    auto parent = GetParent();
    if (parent != nullptr)
    {
        parent->UpdateInfo();
        m_info.modelMat = parent->GetInfo().modelMat;
    }
}

void CAGD::AIS_Box::RecvMessage(Message mess)
{
    // 包围盒不活跃则不接受消息
    if (m_info.active)
    {
        // 先调用默认接收函数
        AIS_Base::RecvMessage(mess);

        // 收到移动消息，刷新
        switch (mess)
        {
        case CAGD::Message::SHOW_INFO: {
            m_info.status = AIS_Status::NONE;
            UpdateArray();
            break;
        }
        case CAGD::Message::HIDE_INFO: {
            // 隐藏时移除所有状态
            m_info.status = AIS_Status::HIDDEN;
            break;
        }
        default:
            break;
        }
    }
}

std::vector<CAGD::BPntf> CAGD::AIS_Box::GetPoints() const
{
    // 获得需要绘制的顶点
    std::vector<BPnt> box;
    box.push_back(m_box.center + m_box.x2 + m_box.y2 + m_box.z1);
    box.push_back(m_box.center + m_box.x1 + m_box.y2 + m_box.z1);
    box.push_back(m_box.center + m_box.x1 + m_box.y2 + m_box.z2);
    box.push_back(m_box.center + m_box.x2 + m_box.y2 + m_box.z2);
    box.push_back(m_box.center + m_box.x2 + m_box.y1 + m_box.z1);
    box.push_back(m_box.center + m_box.x1 + m_box.y1 + m_box.z1);
    box.push_back(m_box.center + m_box.x1 + m_box.y1 + m_box.z2);
    box.push_back(m_box.center + m_box.x2 + m_box.y1 + m_box.z2);

    // 保存所有顶点
    std::vector<BPntf> points;

#define PASS_FACE(index0, index1, index2, index3)                                                                      \
    {                                                                                                                  \
        points.push_back(box[index0]);                                                                                 \
        points.push_back(box[index1]);                                                                                 \
        points.push_back(box[index2]);                                                                                 \
        points.push_back(box[index3]);                                                                                 \
    }

    // 传递 5 个面的顶点
    PASS_FACE(0, 1, 2, 3)
    PASS_FACE(0, 3, 7, 4)
    PASS_FACE(0, 4, 5, 1)
    PASS_FACE(4, 7, 6, 5)
    PASS_FACE(1, 5, 6, 2)

#undef PASS_FACE

    return points;
}

CAGD::BBox CAGD::AIS_Box::GetBBox() const
{
    return m_box;
}

bool CAGD::AIS_Box::Collision(Point pos) const
{
    float z1 = 0.8;
    auto &context = m_context;
    auto invModel = Transform::Inverted(m_info.modelMat);
    BPnt q1 = Transform::Perform(invModel, context.GetSpacePoint(pos, z1));
    BPnt q2 = Transform::Perform(invModel, context.GetInfo().viewPos);
    BVec v = q1 - q2;

    // 获得需要绘制的顶点
    std::vector<BPnt> box;
    box.push_back(m_box.center + m_box.x2 + m_box.y2 + m_box.z1);
    box.push_back(m_box.center + m_box.x1 + m_box.y2 + m_box.z1);
    box.push_back(m_box.center + m_box.x1 + m_box.y2 + m_box.z2);
    box.push_back(m_box.center + m_box.x2 + m_box.y2 + m_box.z2);
    box.push_back(m_box.center + m_box.x2 + m_box.y1 + m_box.z1);
    box.push_back(m_box.center + m_box.x1 + m_box.y1 + m_box.z1);
    box.push_back(m_box.center + m_box.x1 + m_box.y1 + m_box.z2);
    box.push_back(m_box.center + m_box.x2 + m_box.y1 + m_box.z2);

    // 进行碰撞检测
    bool collision = false;

#define INT_FACE(index0, index1, index2, index3)                                                                       \
    {                                                                                                                  \
        std::vector<BPnt> points;                                                                                      \
        points.push_back(box[index0]);                                                                                 \
        points.push_back(box[index1]);                                                                                 \
        points.push_back(box[index2]);                                                                                 \
        points.push_back(box[index3]);                                                                                 \
        collision = collision || Convex::InProjectHull(q2, v, points);                                                 \
    }

    // 传递 6 个面的顶点
    INT_FACE(0, 1, 2, 3)
    INT_FACE(0, 3, 7, 4)
    INT_FACE(0, 4, 5, 1)
    INT_FACE(4, 7, 6, 5)
    INT_FACE(1, 5, 6, 2)
    INT_FACE(2, 6, 7, 3)

#undef INT_FACE

    return collision;
}